﻿namespace Profit
{
    using System;
    using System.Diagnostics;
    using System.Globalization;
    using System.IO;
    using System.Reflection;
    using System.Windows;
    using Diagnostic;
    using Properties;
    using Services;
    using ViewModels;
    using ViewModels.Interfaces;
    using Views;

    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : Application
    {
        private const string LOG_FILE = "profit.log";

        private static readonly TraceSource AppTrace = new TraceSource("Profit", SourceLevels.All);
        private static readonly TraceEventsObservableCollection LastEvents = new TraceEventsObservableCollection(10);
        private IViewModel _mainViewmodel;
        private static CustomTraceListener _customlistener;

        /// <summary>
        /// Obtains the application trace source
        /// </summary>
        internal static TraceSource Trace
        {
            get { return AppTrace; }
        }
        /// <summary>
        /// Obtains the events collection history 
        /// </summary>
        internal static TraceEventsObservableCollection Events
        {
            get { return LastEvents; }
        }
        /// <summary>
        /// Clears recent events
        /// </summary>
        internal void ClearEvents()
        {
            LastEvents.Clear();
        }

        /// <summary>
        /// Raises the <see cref="E:System.Windows.Application.Startup"/> event.
        /// </summary>
        /// <param name="e">A <see cref="T:System.Windows.StartupEventArgs"/> that contains the event data.</param>
        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);
            this.DispatcherUnhandledException += OnUnhandledException;
           
            Trace.Listeners.Clear();

            if(Debugger.IsAttached)
                Trace.Listeners.AddRange(Debug.Listeners);

            if(Settings.Default.UseLog)
            {
                if (String.IsNullOrEmpty(Settings.Default.PathLog))
                    Settings.Default.PathLog = ".";

                _customlistener = new CustomTraceListener(Path.Combine(new[]{ Path.GetFullPath( Settings.Default.PathLog ), LOG_FILE}), false);
                _customlistener.NewEvent += OnNewEvent;
                Trace.Listeners.Add(_customlistener);

                System.Diagnostics.Trace.Listeners.Add(_customlistener);
            }

            Trace.TraceInformation("[Starting] {0}", GetApplicationInfos());

            Repository.Default.Initialize();

            _mainViewmodel = new MainViewModel(new MainView());
            _mainViewmodel.View.Show();
        }

        /// <summary>
        /// Raises the <see cref="E:System.Windows.Application.Exit"/> event.
        /// </summary>
        /// <param name="e">An <see cref="T:System.Windows.ExitEventArgs"/> that contains the event data.</param>
        protected override void OnExit(ExitEventArgs e)
        {
            _mainViewmodel = null;
            Repository.Default.Dispose();
            RegistryUserSettings.Default.Dispose();

            // Saving user settings
            Settings.Default.Save();
            
            this.DispatcherUnhandledException -= OnUnhandledException;
            Trace.Flush();
            Trace.Close();
            Trace.Listeners.Clear();

            _customlistener.NewEvent -= OnNewEvent;
            _customlistener.Dispose();
            _customlistener = null;

            base.OnExit(e);
        }
        /// <summary>
        /// Unhandled Exception event handler
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        static void OnUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
        {
            Trace.TraceEvent(TraceEventType.Critical, 0, "UnhandledException: {0} {1}, Stack: {2}", e.Exception.GetType(), e.Exception.Message, e.Exception.StackTrace);
            Trace.Flush();
        }

        private void OnNewEvent(object sender, TraceEventArgs e)
        {
            if (!base.Dispatcher.CheckAccess())
                base.Dispatcher.Invoke(new ActionDelegate<TraceEventArgs>(LastEvents.Add), e);
            else
                LastEvents.Add(e);
        }

        private static string GetApplicationInfos()
        {
            return String.Format(
                CultureInfo.InvariantCulture, 
                "Version: {0}, Cultures: {1}, UI: {2}", 
                Assembly.GetEntryAssembly().GetName().Version, 
                CultureInfo.CurrentCulture,
                CultureInfo.CurrentUICulture);
        }
    }
}
